package ferp.android.tasks.center;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.widget.TextView;
import com.google.gson2.reflect.TypeToken;
import ferp.android.BuildConfig;
import ferp.android.activities.preferences.Preferences;
import ferp.android.ads.interstitial.InterstitialAdManager;
import ferp.android.managers.PollManager;
import ferp.android.managers.ProfileManager;
import ferp.center.client.Action;
import ferp.center.network.RequestConfigGet;
import ferp.center.network.ResponseConfigGet;
import ferp.core.Message;
import ferp.core.ai.strategy.simple.SimpleBidding;
import ferp.core.game.Game;
import ferp.core.game.Levels;
import ferp.core.log.Log;
import ferp.core.player.Profile;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Date;

/**
 * User: igorgok
 * Date: 12/9/12 5:14 PM
 */
public class TaskCenterConfigGet extends AsyncTask<Void, Void, Collection<Message>>
{
  public static void execute(Context context, ProfileManager pm, TextView mtv)
  {
    if (pm.getCurrentProfile() != null)
      new TaskCenterConfigGet(context, pm, mtv).execute();
  }

  public static float getBidContributionThreshold(SharedPreferences sp) {return sp.getInt(CONFIG_BID_NN_THRESHOLD, 0);}

  protected TaskCenterConfigGet(Context context, ProfileManager pm, TextView mtv)
  {
    this.context = context.getApplicationContext();
    this.device = Preferences.getDeviceID(context);
    this.pm = pm;
    this.mtv = mtv;
  }

  @Override
  protected Collection<Message> doInBackground(Void... voids)
  {
    Collection<Message> messages = null;

    try
    {
      SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
      long last = preferences.getLong(CONFIG_LAST_UPDATED, 0), now = System.currentTimeMillis();

      // request NN config once a day to reduce traffic unless we're in debug mode
      if (BuildConfig.DEBUG || last == 0 || now - last > MS_IN_DAY)
      {
        Profile profile = pm.getCurrentProfile();
        RequestConfigGet request = new RequestConfigGet();
        String nnj = null;

        // get current config ID
        request.device = device;
        request.version = pm.version();
        request.date = new Date();
        request.locale = profile.settings.locale;
        request.id = preferences.getLong(CONFIG_ID, 0);
        request.profile = profile == null ? 0 : profile.centerId;
        request.lastPollID = PollManager.getLastPollID(preferences);

        // make the request
        ResponseConfigGet response = Action.execute(Action.CONFIG_GET, request, ResponseConfigGet.class);

        if (response != null)
        {
          // enable editing preferences
          SharedPreferences.Editor editor = preferences.edit();

          editor.putLong(CONFIG_LAST_UPDATED, now);
          // save configuration ID only if its new
          if (response.id != request.id)
            editor.putLong(CONFIG_ID, response.id);
          // save enabled state
          if (response.bidding != null)
          {
            editor.putBoolean(CONFIG_BID_NN_ENABLE, response.bidding.enable);
            // if there is a new NN configuration store it locally
            if (response.bidding.nnj != null)
            {
              nnj = response.bidding.nnj;
              editor.putString(CONFIG_BID_NN_DATA, response.bidding.nnj);
            }
            // save bid contributor score threshold
            editor.putInt(CONFIG_BID_NN_THRESHOLD, response.bidding.threshold);
          }
          else
            // something wrong with the bidding configuration, disable bidding with NN
            editor.putBoolean(CONFIG_BID_NN_ENABLE, false);

          // get levels information
          if (response.levels != null)
          {
            editor.putString(CONFIG_LEVELS_DATA, response.levels.data);

            Log.debug(Log.TAG, "new opponent levels configuration: " + response.levels.data);
          }

          // retrieve messages
          if (response.messages != null)
            editor.putString(CONFIG_MESSAGE_DATA, response.messages);

          // save interstitial flag
          editor.putString(CONFIG_AD, Game.gson.toJson(response.ad));

          editor.commit();

          // set poll - disable in e-book version
          //PollManager.set(context.getResources(), response.poll);

          Log.debug(Log.TAG, (nnj == null ? "no new bidding NN configuration received" : ("downloaded bidding NN configuration of size " + nnj.length())));
        }
        else
          Log.debug(Log.TAG, "failed to receive bidding NN configuration");
      }

      // setup the bidding NN
      SimpleBidding.init(Game.gson, preferences.getBoolean(CONFIG_BID_NN_ENABLE, false) ? preferences.getString(CONFIG_BID_NN_DATA, null) : null);
      // update opponent levels information
      Levels.update(Game.gson, preferences.getString(CONFIG_LEVELS_DATA, null));
      // load messages
      messages = Game.gson.fromJson(preferences.getString(CONFIG_MESSAGE_DATA, null), ListOfMessages);

      // update interstitial display enabled state
      ResponseConfigGet.Ad ad = Game.gson.fromJson(preferences.getString(CONFIG_AD, null), ResponseConfigGet.Ad.class);
      InterstitialAdManager.setEnabled(false); //ad != null && ad.interstitial != null && ad.interstitial.enabled);
    }
    catch (Exception e)
    {
      Log.error(Action.TAG, e);
    }

    return messages;
  }

  private static final Type ListOfMessages = new TypeToken<Collection<Message>>(){}.getType();
  private static final String MESSAGE_DELIMITER = Message.NBSP + Message.NBSP + "<font color=\"yellow\"><b>•</b></font>" + Message.NBSP + Message.NBSP;

  @Override
  protected void onPostExecute(Collection<Message> messages)
  {
    super.onPostExecute(messages);

    // handle messages
/*
    if (messages != null && messages.size() > 0)
    {
      int version = ProfileManager.instance(context).version().code;
      Date now = new Date();
      StringBuilder sb = new StringBuilder(1024);

      for (Message m : messages)
        if (m.fits(version, now))
          sb.append(MESSAGE_DELIMITER).append(m.text);

      // debug
      //sb.append(MESSAGE_DELIMITER).append(Message.image("human")).append(" vs ").append(Message.image("android"));
      //sb.append(MESSAGE_DELIMITER).append("No images");

      sb.append(MESSAGE_DELIMITER);

      Animation transparency = new AlphaAnimation(1f, 0f);

      transparency.setDuration(0);
      transparency.setFillAfter(true);

      mtv.setSelected(true);
      mtv.startAnimation(transparency);
      mtv.setVisibility(View.VISIBLE);
      mtv.setTypeface(GUI.Font.NORMAL);

      try
      {
        Object marquee = getMarqueeObject(mtv);
        Field speed = getMarqueeSpeedField(marquee);

        speed.setFloat(marquee, speed.getFloat(marquee) * 2);
      }
      catch (Exception e)
      {
        Log.error(Log.TAG, e);
      }

      mtv.setText(Html.fromHtml(sb.toString(), new Html.ImageGetter()
      {
        @Override
        public Drawable getDrawable(String s)
        {
          Resources r = context.getResources();
          int id = r.getIdentifier(s, "drawable", context.getPackageName());
          Drawable d = r.getDrawable(id);
          int h = Math.round((mtv.getHeight() - mtv.getPaddingBottom() - mtv.getPaddingTop()) * 0.5f);

          // limit the dimensions
          d.setBounds(0, -h - 1, h * 2 - 1, h);

          return d;
        }
      }, null));

      Animation appear = new AlphaAnimation(0f, 1f);

      appear.setDuration(1000);
      appear.setFillAfter(true);

      mtv.startAnimation(appear);

      mtv.setOnTouchListener(new View.OnTouchListener()
      {
        @Override
        public boolean onTouch(View view, MotionEvent me)
        {
          if (me.getAction() != MotionEvent.ACTION_DOWN)
            return false;

          int w = view.getWidth(), back = w / 3, forward = back * 2;
          int x = Math.round(me.getX());

          try
          {
            if (mo == null)
            {
              mo = getMarqueeObject(mtv);

              if (mo != null)
              {
                speed.field = getMarqueeSpeedField(mo);
                speed.initial = speed.field.getFloat(mo);
                speed.change = speed.initial / 4;
              }
            }

            if (mo != null)
            {
              float s = speed.field.getFloat(mo);

              if (x > forward)
                speed.field.setFloat(mo, s == 0 ? speed.initial : s + speed.change);
              else
                if (x > back)
                {
                  speed.field.setFloat(mo, s == 0 ? speed.before : 0);
                  speed.before = s;
                }
                else
                  speed.field.setFloat(mo, s == 0 ? -speed.initial : s - speed.change);
            }
          }
          catch (Exception e)
          {
            Log.error(Log.TAG, e);
          }

          return true;
        }

        final class Speed
        {
          private Field field;
          private float initial;
          private float before;
          private float change;
        }

        private Object mo;
        private final Speed speed = new Speed();
      });
    }
    else
      mtv.setVisibility(View.INVISIBLE);
*/
  }

  // number of milliseconds in day
  private static final long MS_IN_DAY = 24 * 60 * 60 * 1000;

  // names for stored values
  // bidding NN
  private static final String CONFIG_ID               = "config_id";
  private static final String CONFIG_LAST_UPDATED     = "config_last_updated";
  private static final String CONFIG_BID_NN_ENABLE    = "config_bid_nn_enabled";
  private static final String CONFIG_BID_NN_DATA      = "config_bid_nn_data";
  private static final String CONFIG_BID_NN_THRESHOLD = "config_bid_nn_threshold";
  private static final String CONFIG_MESSAGE_DATA     = "config_message_data";
  // opponent levels
  private static final String CONFIG_LEVELS_DATA = "config_levels_data";
  // interstitial ad flag
  private static final String CONFIG_AD = "config_ad";

  private final Context context;
  private final String device;
  private final ProfileManager pm;
  private final TextView mtv;

  private Field getAccessibleField(Object object, String name) throws NoSuchFieldException
  {
    Field f = object.getClass().getDeclaredField(name);

    f.setAccessible(true);

    return f;
  }

  private Object getMarqueeObject(TextView tv) throws NoSuchFieldException, IllegalAccessException
  {
    return getAccessibleField(tv, "mMarquee").get(tv);
  }

  private Field getMarqueeSpeedField(Object marquee) throws NoSuchFieldException
  {
    return getAccessibleField(marquee, "mScrollUnit");
  }
}
